#region Copyright (c) 2006-2009 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2009 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Text;
using Widgetsphere.Generator.Common.GeneratorFramework;
using Widgetsphere.Generator;
using Widgetsphere.Generator.Models;
using System.Xml;
using Widgetsphere.Generator.Common.Util;

namespace Widgetsphere.Generator.ProjectItemGenerators
{
	public abstract class BaseGenerator : IProjectItemGenerator
	{
		#region Class Member

    protected ModelRoot _model;
    //private static ModelRoot _tempModel;
    //private byte[] hash = null;

		#endregion

		#region IProjectItemGenerator Members

    public event System.EventHandler GenerationStarted;
		public event ProjectItemGenerationCompleteEventHandler GenerationComplete;
		public event ProjectItemGeneratedEventHandler ProjectItemGenerated;

    public virtual void Initialize(IModelObject model)
    {
      try
      {
				//THIS WAS CAUSING A RELOAD FOR EVERY GENERATOR, THIS DOES NOT NEED TO OCCUR
				//ModelRoot newModel = new ModelRoot(null);
				//XmlDocument oDoc = new XmlDocument();
				//oDoc.LoadXml("<ModelRoot></ModelRoot>");
				//model.XmlAppend(oDoc.DocumentElement);
				//newModel.XmlLoad(oDoc.DocumentElement);
				//_model = newModel;

				_model = (ModelRoot)model;

        bool hasMetaData = false;
        foreach (Table table in _model.Database.Tables)
        {
          if (table.CreateMetaData)
            hasMetaData = true;
        }

        Table projectItemDataType = null;
        if (hasMetaData)
        {
          #region Create the PROPERTY_ITEM_DATA_TYPE table
          projectItemDataType = _model.Database.Tables.Add("PROPERTY_ITEM_DATA_TYPE");
          projectItemDataType.IsMetaDataMaster = true;

          Column column = null;
          column = _model.Database.Columns.Add("property_item_data_type_id");
          column.ParentTableRef = projectItemDataType.CreateRef();
          column.Type = System.Data.SqlDbType.Int;
          column.PrimaryKey = true;
          column.Identity = IdentityTypeConstants.None;
          column.AllowNull = false;
          projectItemDataType.Columns.Add(column.CreateRef());

          column = _model.Database.Columns.Add("name");
          column.ParentTableRef = projectItemDataType.CreateRef();
          column.Type = System.Data.SqlDbType.VarChar;
          column.Length = 50;
          column.AllowNull = false;
          projectItemDataType.Columns.Add(column.CreateRef());
          #endregion
        }

        foreach (Table table in _model.Database.Tables)
        {
          if (table.CreateMetaData)
          {
            Column column = null;

            #region Create the PROPERTY_ITEM_DEFINE table
            System.Diagnostics.Debug.WriteLine("PROPERTY_ITEM_DEFINE: " + table.DatabaseName);
            Table projectItemDefineTable = _model.Database.Tables.Add(table.DatabaseName + "_PROPERTY_ITEM_DEFINE");
            projectItemDefineTable.IsMetaDataDefinition = true;

            column = _model.Database.Columns.Add("property_item_define_id");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.PrimaryKey = true;
            column.Identity = IdentityTypeConstants.Database;
            column.AllowNull = false;
            projectItemDefineTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("name");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.VarChar;
            column.Length = 50;
            column.AllowNull = false;
            column.GridVisible = true;
            column.SortOrder = 0;
            column.FriendlyName = "Name";
            projectItemDefineTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("property_item_data_type");
            column.EnumType = "PropertyBagDataTypeConstants";
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.GridVisible = true;
            column.SortOrder = 1;
            column.FriendlyName = "Data type";
            column.AllowNull = false;
            projectItemDefineTable.Columns.Add(column.CreateRef());

            //RELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATION
            //Add a relation to from the datatype table to this one
            Relation relation2 = _model.Database.Relations.Add();
            relation2.ParentTableRef = projectItemDataType.CreateRef();
            relation2.ChildTableRef = projectItemDefineTable.CreateRef();
            ColumnRelationship relationship = new ColumnRelationship(relation2.Root);
            relationship.ParentColumnRef = ((Column)projectItemDataType.Columns[0].Object).CreateRef();
            relationship.ChildColumnRef = column.CreateRef();
            relation2.ColumnRelationships.Add(relationship);
            projectItemDataType.Relationships.Add(relation2.CreateRef());
            //RELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATIONRELATION            

            column = _model.Database.Columns.Add("group");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.VarChar;
            column.Length = 50;
            column.AllowNull = true;
            column.GridVisible = true;
            column.SortOrder = 2;
            column.FriendlyName = "Group";
            projectItemDefineTable.Columns.Add(column.CreateRef());
                        
            column = _model.Database.Columns.Add("sort_index");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.AllowNull = false;
            column.GridVisible = true;
            column.SortOrder = 3;
            column.FriendlyName = "Sort order";
            projectItemDefineTable.Columns.Add(column.CreateRef());
            
            column = _model.Database.Columns.Add("minimum_value");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.VarChar;
            column.Length = 50;
            column.GridVisible = true;
            column.SortOrder = 4;
            column.FriendlyName = "Minimum value";
            projectItemDefineTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("maximum_value");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.VarChar;
            column.Length = 50;
            column.GridVisible = true;
            column.SortOrder = 5;
            column.FriendlyName = "Maximum value";
            projectItemDefineTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("max_length");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.GridVisible = true;
            column.SortOrder = 6;
            column.FriendlyName = "Maximum Length";
            projectItemDefineTable.Columns.Add(column.CreateRef());


            column = _model.Database.Columns.Add("is_required");
            column.ParentTableRef = projectItemDefineTable.CreateRef();
            column.Type = System.Data.SqlDbType.Bit;
            column.AllowNull = false;
            column.GridVisible = true;
            column.SortOrder = 7;
            column.FriendlyName = "Required";
            projectItemDefineTable.Columns.Add(column.CreateRef());

            #endregion

            #region Create the PROPERTY_ITEM table
            //System.Diagnostics.Debug.WriteLine("PROPERTY_ITEM: " + table.DatabaseName);
            Table projectItemValueTable = _model.Database.Tables.Add(table.DatabaseName + "_PROPERTY_ITEM");
            projectItemValueTable.IsMetaData = true;

            column = _model.Database.Columns.Add("property_item_id");
            column.ParentTableRef = projectItemValueTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.PrimaryKey = true;
            column.AllowNull = false;
            column.Identity = IdentityTypeConstants.Database;
            projectItemValueTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("property_item_define_id");
            column.ParentTableRef = projectItemValueTable.CreateRef();
            column.Type = System.Data.SqlDbType.Int;
            column.AllowNull = false;
            projectItemValueTable.Columns.Add(column.CreateRef());

            column = _model.Database.Columns.Add("item_value");
            column.ParentTableRef = projectItemValueTable.CreateRef();
            column.Type = System.Data.SqlDbType.VarChar;
            column.Length = 1024;
            column.AllowNull = false;
            projectItemValueTable.Columns.Add(column.CreateRef());

            //Create all primary keys
            foreach (Column pkColumn in table.PrimaryKeyColumns)
            {
              column = _model.Database.Columns.Add(pkColumn.DatabaseName);
              column.ParentTableRef = projectItemValueTable.CreateRef();
              column.Type = pkColumn.Type;
              column.Length = pkColumn.Length;
              column.AllowNull = false;
              projectItemValueTable.Columns.Add(column.CreateRef());
            }

            //Add relationship between Definition and Value table
            if (true)
            {
              Relation relation = new Relation(this._model);
              relation.ParentTableRef = projectItemDefineTable.CreateRef();
              relation.ChildTableRef = projectItemValueTable.CreateRef();
              ColumnRelationship colRel = new ColumnRelationship(_model);
              colRel.ParentColumnRef = projectItemDefineTable.Columns["property_item_define_id"];
              colRel.ChildColumnRef = projectItemValueTable.Columns["property_item_define_id"];
              relation.ColumnRelationships.Add(colRel);
              relation.RoleName = "";
              _model.Database.Relations.Add(relation);
              projectItemDefineTable.Relationships.Add(relation.CreateRef());
            }

            //Add relationship between Value table and primary table
            if (true)
            {
              Relation relation = new Relation(this._model);
              relation.ParentTableRef = table.CreateRef();
              relation.ChildTableRef = projectItemValueTable.CreateRef();
              foreach (Column pkColumn in table.PrimaryKeyColumns)
              {
                ColumnRelationship colRel = new ColumnRelationship(_model);
                colRel.ParentColumnRef = table.Columns[pkColumn.DatabaseName];
                colRel.ChildColumnRef = projectItemValueTable.Columns[pkColumn.DatabaseName];
                relation.RoleName = "";
                relation.ColumnRelationships.Add(colRel);
                table.Relationships.Add(relation.CreateRef());
              }
              _model.Database.Relations.Add(relation);
            }

            #endregion
          }
        }

        //_model = (ModelRoot)model;

      }
      catch (Exception ex)
      {
        throw;
      }

    }

    protected virtual void OnGenerationStart(object sender, System.EventArgs e)
    {      
      if (this.GenerationStarted != null)
      {
        this.GenerationStarted(sender, e);
      }
    }

		protected virtual void OnProjectItemGenerated(object sender, ProjectItemGeneratedEventArgs pigArgs )
		{
			if(this.ProjectItemGenerated != null)
			{
				this.ProjectItemGenerated(sender, pigArgs);
			}
		}

		protected virtual void OnGenerationComplete(object sender, ProjectItemGenerationCompleteEventArgs args)
		{      
			if(this.GenerationComplete != null)
			{
				this.GenerationComplete(sender, args);
			}      
		}

		#endregion

		#region Methods

		public abstract void Generate();
		protected abstract string ProjectName{get;}
    public abstract int FileCount { get;}

		#endregion


	}
}
